package simple3D.core 
{
	import core.IDisposable;
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.TriangleCulling;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	import simple3D.materials.Material3D;
	import simple3D.utils.MathUtil;
	/**
	 * ...
	 * @author Dmitriy Gaiduk
	 */
	public class Surface3D extends DisplayObject3D
	{
		
		private var points:Vector.<Vector3D>;
		private var vertices:Vector.<Number>;
		private var indices:Vector.<int>
		private var uvt:Vector.<Number>;
		private var _material:Material3D;
		
		public var userData:Object;
		
		//public var surfaceName:String = "";
		//private var centrPoint:Vector3D = new Vector3D();
		public var shapeWidth:Number = 0;
		public var index:int;
		public var showCentrPoint:Boolean = false;
		
		public function Surface3D(points:Vector.<Vector3D>, indices:Vector.<int>, uvt:Vector.<Number>, 
									material:Material3D) 
		{
			super();
			this.points = points;
			this.indices = indices;
			this.uvt = uvt;
			_material = material;
			//initial settings
			getCentrPoint();
		}
		
		private function getCentrPoint():void
		{
			if (points == null)
			{
				return;
			}
			var pointTopLeft:Vector3D = new Vector3D(points[0].x, points[0].y, points[0].z);
			var pointRightDown:Vector3D = new Vector3D(points[0].x, points[0].y, points[0].z);
			for each (var v:Vector3D in points)
			{
				// min
				if (v.x < pointTopLeft.x)
				{
					pointTopLeft.x = v.x;
				}
				if (v.y < pointTopLeft.y)
				{
					pointTopLeft.y = v.y;
				}
				if (v.z < pointTopLeft.z)
				{
					pointTopLeft.z = v.z;
				}
				//max
				if (v.x > pointRightDown.x)
				{
					pointRightDown.x = v.x;
				}
				if (v.y > pointRightDown.y)
				{
					pointRightDown.y = v.y;
				}
				if (v.z > pointRightDown.z)
				{
					pointRightDown.z = v.z;
				}
			}
			
			centrPoint.x = pointTopLeft.x + (pointRightDown.x - pointTopLeft.x) * 0.5;
			centrPoint.y = pointTopLeft.y + (pointRightDown.y - pointTopLeft.y) * 0.5;
			centrPoint.z = pointTopLeft.z + (pointRightDown.z - pointTopLeft.z) * 0.5;
		}
		
		override public function updateView():void 
		{
			super.updateView();
			if (points == null)
			{
				return;
			}
		
			vertices = new Vector.<Number>();
			var uvtIndex:uint = 2; // u=0, v=1, t=2, ... index t[n]=n*3 + 2
			var len:uint = indices.length;
			var pointTopLeft:Vector3D = new Vector3D(points[0].x, points[0].y, points[0].z);
			var pointRightDown:Vector3D = new Vector3D(points[0].x, points[0].y, points[0].z);
			
			for each (var v:Vector3D in points)
			{
				//get rotated position
				var adjustedV:Vector3D = rotateAndTranslate(v);
				//calculate vertices
				var perspective:Number = calcPerspective(adjustedV.z);
				//perspective = 1;
				vertices.push(adjustedV.x*perspective, adjustedV.y*perspective);
				//update uvt
				if (uvt != null)
				{
					uvt[uvtIndex] = perspective;
					uvtIndex += 3; // u=0, v=1, t=2, ... index t[n]=n*3 + 2
				}
			}
			//clear existing graphics
			graphics.clear();
			//draw
			//_material.beginFill(graphics);
			_material.drawTriangles(graphics, vertices, indices, uvt, TriangleCulling.NONE);
			if (showCentrPoint)
			{
				drawCentrPoint();
			}
		}
		
		public function get material():Material3D 
		{
			return _material;
		}
		
		// TODO destroy material
		public function set material(value:Material3D):void 
		{
			_material = value;
		}
		
		/**
		 * Refernces to Null, without destoy  objects
		 */
		public function clearReferences():void
		{
			_material = null;
			if (points != null && points.length>0)
			{
				points.splice(0, points.length);
			}
			points = null;
			
			if (vertices != null && vertices.length>0)
			{
				vertices.splice(0, vertices.length);
			}
			vertices = null;
			
			if (indices != null && indices.length>0)
			{
				indices.splice(0, indices.length);
			}
			indices = null;
			
			if (uvt != null && uvt.length>0)
			{
				uvt.splice(0, uvt.length);
			}
			uvt = null;
		}
		
		public function destroy():void
		{
			_material = null;
			if (points != null && points.length>0)
			{
				points.splice(0, points.length);
			}
			points = null;
			
			if (vertices != null && vertices.length>0)
			{
				vertices.splice(0, vertices.length);
			}
			vertices = null;
			
			if (indices != null && indices.length>0)
			{
				indices.splice(0, indices.length);
			}
			indices = null;
			
			if (uvt != null && uvt.length>0)
			{
				uvt.splice(0, uvt.length);
			}
			uvt = null;
			
			if (userData is IDisposable)
			{
				(userData as IDisposable).dispose();
			}
		}
		
	}

}